package view;

import java.awt.*;
import java.awt.event.*;
import java.util.HashMap;

import javax.swing.*;

import controller.ConnectionTester;
import model.environmentConfig.*;

public class CanvasPanel extends JPanel implements MouseListener, MouseMotionListener{
	private Point draggingMousePoint;
	private Object draggingObject;
	
	public CanvasPanel(){
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
	}
	
	@Override
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		if(ConnectionTester.getEnvironmentConfig()!=null){
			drawEnvConf((Graphics2D)g, ConnectionTester.getEnvironmentConfig());
		}
	}
	
	private void drawEnvConf(Graphics2D g, EnvironmentConfiguration envConf){
		int x1, x2, y1, y2;
		HashMap<Long, Node> nodes=envConf.getNodes();
		Stroke originalStroke=g.getStroke();
		Color originalColor=g.getColor();
		
		try{
			for(CommunicationChannel channel:envConf.getChannels()){
				g.setColor(channel.getState().getColor());
				
				if(channel.equals(envConf.getSelectedObj())){
					g.setStroke(new BasicStroke(3));
				}
				x1=(int)nodes.get(channel.getInitiatorNode()).getDisplayData().getCenter().getX();
				y1=(int)nodes.get(channel.getInitiatorNode()).getDisplayData().getCenter().getY();
				x2=(int)nodes.get(channel.getListeningNode()).getDisplayData().getCenter().getX();
				y2=(int)nodes.get(channel.getListeningNode()).getDisplayData().getCenter().getY();
				g.drawLine(x1, y1, x2, y2);
				g.setStroke(originalStroke);
			}
			
			for(Node node:nodes.values()){
				if(node.equals(envConf.getSimulatingNode())){
					g.setColor(new Color(16070058));
				}
				else{
					g.setColor(node.getNodeState().getColor());
				}
				if(node.equals(envConf.getSelectedObj())){
					g.setStroke(new BasicStroke(3));
				}
				g.drawRect(
					(int)node.getDisplayData().getX(),
					(int)node.getDisplayData().getY(),
					(int)node.getDisplayData().getWidth(),
					(int)node.getDisplayData().getHeight()
				);
				g.setStroke(originalStroke);
			}
			
			g.setColor(originalColor);
		}
		catch(NullPointerException e){
			if(!fixNodes(nodes)){
				throw(e);
			}
			else{
				g.setStroke(originalStroke);
				MainFrame.refresh();
			}
		}
	}
	
	private boolean fixNodes(HashMap<Long, Node> nodes){
		boolean fixedNode=false;

		for(Node node:nodes.values()){
			if(node.getDisplayData()==null){
				node.setDisplayData(new NodeRectangle());
				fixedNode=true;
			}
		}
		
		return(fixedNode);
	}

	@Override
	public void mouseClicked(MouseEvent e){
	}

	@Override
	public void mouseEntered(MouseEvent e){
	}

	@Override
	public void mouseExited(MouseEvent e){
	}

	@Override
	public void mousePressed(MouseEvent e){
		EnvironmentConfiguration envConf=ConnectionTester.getEnvironmentConfig();
		if(envConf==null){
			return;
		}

		draggingMousePoint=e.getPoint();
		
		for(Node node:envConf.getNodes().values()){
			if(node.getDisplayData().contains(e.getPoint())){
				draggingObject=node;
				return;
			}
		}
		
		for(CommunicationChannel channel:envConf.getChannels()){
			if(channel.overlaps(e.getPoint())){
				draggingObject=channel;
				return;
			}
		}
	}

	@Override
	public void mouseReleased(MouseEvent e){
		EnvironmentConfiguration envConf=ConnectionTester.getEnvironmentConfig();
		if(envConf==null){
			return;
		}
		envConf.setSelectedObj(draggingObject);
		refreshAttributesPanel();
		draggingObject=null;
		MainFrame.refresh();
	}
	public void refreshAttributesPanel(){
		Object obj = getParent();
		if(obj instanceof EnvironmentConfigDesignerPanel){
			((EnvironmentConfigDesignerPanel)getParent()).refreshAttributesPanel();
		}
		else
			((MainPanel)getParent()).refreshAttributesPanel();
	}
	@Override
	public void mouseDragged(MouseEvent e){
		if(draggingObject==null){
			return;
		}
		
		if(draggingObject instanceof Node){
			double dx=e.getPoint().getX()-draggingMousePoint.getX();
			double dy=e.getPoint().getY()-draggingMousePoint.getY();
			((Node)draggingObject).getDisplayData().translate(dx, dy);
			draggingMousePoint=e.getPoint();
		}
		
		MainFrame.refresh();
	}

	@Override
	public void mouseMoved(MouseEvent e){
	}
}
